package se.ytterman.jpcap.data.bytearray;

import java.lang.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;

import se.ytterman.jpcap.data.BinaryData;

public class ArrayBinaryData extends BinaryData {

    public ArrayBinaryData(int array_length) {
	// Create default buffer
	this.byte_buffer = new byte[array_length];

	// Set payload length
	this.payload_length = array_length;
    }

    public ArrayBinaryData(byte[] byte_buffer) {
	// Create default buffer
	this.byte_buffer = byte_buffer;

	// Set payload length
	this.payload_length = byte_buffer.length;
    }

    public ArrayBinaryData(int array_length, InputStream frameDataStream) throws Exception {
	// Call other constructor
	this(array_length);

	// Read data
	this.read(frameDataStream);
    }

    public ArrayBinaryData(byte[] byte_buffer, InputStream frameDataStream) throws Exception {
	// Call other constructor
	this(byte_buffer);

	// Read data
	this.read(frameDataStream);
    }

    public ArrayBinaryData(String array_string) throws Exception {
	// Create a byte array output stream
	ByteArrayOutputStream byteArrayBuffer = new ByteArrayOutputStream();

	// Create buffer string matcher
	String array_pattern = "([0-9a-fA-F]{2}:)*([0-9a-fA-F]{2})";
	Pattern arrayPattern = Pattern.compile(array_pattern);
	Matcher arrayMatcher = arrayPattern.matcher(array_string);

	// Match entire pattern
	if(arrayMatcher.matches()) {
	    // Create byte pattern matcher
	    String byte_pattern = "([0-9a-fA-F]{2})"; 
	    Pattern bytePattern = Pattern.compile(byte_pattern);
	    Matcher byteMatcher = bytePattern.matcher(array_string);

	    // Match each part
	    while(byteMatcher.find()) {
		// Extract "byte" value for each part of the byte array address
		String byte_string = byteMatcher.group();
		int byte_value = Integer.parseInt(byte_string, 16);
		
		// Write into the byte array buffer stream
		byteArrayBuffer.write(byte_value);
	    }
	}
	else {
	    System.out.println("This isn't a proper byte array textual definition: " + array_string);
	}

	// Assign the built byte array 
	this.byte_buffer = byteArrayBuffer.toByteArray();
    }

    // equals
    public static boolean equals(ArrayBinaryData part_one, ArrayBinaryData part_two) {
	// Compare the payload of the two frameparts 
	boolean equal = Arrays.equals(part_one.getPayload(), part_two.getPayload());
	
	// Return
	return equal;
    }

    // read
    public void read(InputStream frameInputStream) throws Exception {
	// Read payload data from the stream
	frameInputStream.read(this.byte_buffer, 
			      0, 
			      this.byte_buffer.length);
    }

    // write
    public void write(OutputStream frameOutputStream) throws Exception {
	// Write payload data to stream
	frameOutputStream.write(this.byte_buffer, 
			       0, 
			       this.byte_buffer.length);
    }

    // toString
    public String toString() {
	// Create string builder
	StringBuilder stringBuilder = new StringBuilder(0);

	// Iterate over the byte buffer
	for(int i = 0; i < this.byte_buffer.length; i++) {
	    // Convert each byte to string representation
	    int byte_value = (int)(this.byte_buffer[i] & 0xFF);
	    String byte_string = String.format("%02X", byte_value);

	    // Add the byte string representation to the string
	    stringBuilder.append(byte_string);

	    // Potentially add a separator, do not if it's the last byte
	    if(i < this.byte_buffer.length-1)
		stringBuilder.append(":");
	}

	// Return string value
	return stringBuilder.toString();
    }

    // getPayload
    public byte[] getPayload() {
	return this.byte_buffer;
    }
    
    // Payload storage buffer
    protected byte[] byte_buffer;
}
